/*
 * Copyright (C) 2009 Leandro Aparecido <lehphyro@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.metalframework.jsf.tag;

import java.io.*;

import javax.el.*;
import javax.faces.*;
import javax.faces.component.*;

import org.apache.commons.lang.*;
import org.metalframework.jsf.scope.*;
import org.metalframework.util.*;

import com.sun.facelets.*;
import com.sun.facelets.tag.*;

public class KeepHandler extends TagHandler {

	private static final FacesScopeType DEFAULT_SCOPE = FacesScopeType.PAGE;
	private static final String SUFFIX_OLD = ".old";
	
	private TagAttribute id;
	private TagAttribute value;
	private TagAttribute scope;
	private TagAttribute dependsOn;
	
	public KeepHandler(TagConfig config) {
		super(config);
		this.id = getRequiredAttribute("id");
		this.value = getRequiredAttribute("value");
		this.scope = getAttribute("scope");
		this.dependsOn = getAttribute("dependsOn");
	}
	
	public void apply(FaceletContext ctx, UIComponent parent) throws IOException, FacesException, FaceletException, ELException {
		FacesScope scopeToUse = getScope(ctx);
		
		String name = id.getValue(ctx);
		
		if (dependsOn == null) {
			Object newValue = value.getObject(ctx);
			
			if (scopeToUse.contains(name)) {
				scopeToUse.set(getNameOfOldValue(name), scopeToUse.get(name));
				
				if (!FacesUtils.isPostback() || newValue != null) {
					scopeToUse.set(name, newValue);
				}
			} else {
				scopeToUse.set(name, newValue);
			}
		} else {
			String dependsOnName = dependsOn.getValue(ctx);
			Object oldValue = scopeToUse.get(getNameOfOldValue(dependsOnName));
			Object newValue = scopeToUse.get(dependsOnName);
			
			if (scopeToUse.get(name) == null ||
				!ObjectUtils.equals(oldValue, newValue)) {
				scopeToUse.set(name, value.getObject(ctx));
			}
		}
		
		ctx.setAttribute(name, scopeToUse.get(name));
	}

	protected FacesScope getScope(FaceletContext ctx) {
		FacesScopeType type;
		if (scope == null) {
			type = DEFAULT_SCOPE;
		} else {
			type = FacesScopeType.identify(scope.getValue(ctx));
		}
		
		return FacesScope.getScopeByType(type);
	}
	
	protected String getNameOfOldValue(String name) {
		return name + SUFFIX_OLD;
	}
}
